/*
 *  Copright: 2008 Philipp Leitner, Distributed Systems Group,
 *            TU Wien, leitner@infosys.tuwien.ac.at
 *
 *  This file is part of DAIOS.
 *
 *  DAIOS is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as
 *  published by the Free Software Foundation.
 * 
 *  DAIOS is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with DAIOS.  If not, see
 *  <http://www.gnu.org/licenses/>.
 * 
 */

package at.ac.tuwien.infosys.dsg.daios.framework;

import java.net.URL;

import javax.xml.namespace.QName;

import at.ac.tuwien.infosys.dsg.daios.exceptions.AmbigiousException;
import at.ac.tuwien.infosys.dsg.daios.exceptions.InvocationException;
import at.ac.tuwien.infosys.dsg.daios.exceptions.NoEndpointException;
import at.ac.tuwien.infosys.dsg.daios.exceptions.UnsupportedMessageTypeException;
import at.ac.tuwien.infosys.dsg.daios.framework.interfaces.IDaiosCallback;
import at.ac.tuwien.infosys.dsg.daios.framework.interfaces.IServiceFrontendImplementor;
import at.ac.tuwien.infosys.dsg.daios.framework.structs.DaiosInputMessage;
import at.ac.tuwien.infosys.dsg.daios.framework.structs.DaiosOutputMessage;

/**
 * 
 * The abstract superclass of all service invokers frontends.
 * Implements the interface that all invokers should stick to.
 * 
 * <p>
 * 
 * Part of a GoF Bridge Pattern. Implements the "abstraction"
 * part of the Bridge.
 * 
 * @author philipp
 *
 */
public abstract class ServiceFrontend {
	
	// the service invoker that should be used
	// this is the "bridge" connector
	protected IServiceFrontendImplementor imp = null;
	
	/**
	 * Do a synchronous, blocking, request-response style
	 * call. The client will be blocked until the return
	 * message is delivered.
	 * 
	 * @param message The Daios style input message.
	 * @return The Daios style output message.
	 * 
	 * @throws AmbigiousException
	 * @throws InvocationException
	 * @throws NoEndpointException
	 * @throws UnsupportedMessageTypeException
	 */
	public DaiosOutputMessage requestResponse(DaiosInputMessage message)
		throws AmbigiousException, InvocationException {
		
		if(message == null) {
			DaiosInputMessage m = new DaiosInputMessage();
			return imp.requestResponse(m);
		}
		
		return imp.requestResponse(message);
		
	}
	
	/**
	 * 
	 * Do an asynchronous 'fire and forget'-style call.
	 * The client fires the input message, and does not
	 * expect any kind of answer or confirmation from the
	 * service.
	 * 
	 * @param message The Daios style input message.
	 * 
	 * @throws AmbigiousException
	 * @throws InvocationException
	 * @throws NoEndpointException 
	 * @throws UnsupportedMessageTypeException 
	 */
	public void fireAndForget(DaiosInputMessage message)
		throws AmbigiousException, InvocationException {

		if(message == null) {
			DaiosInputMessage m = new DaiosInputMessage();
			imp.fireAndForget(m);
		}
		
		else
			imp.fireAndForget(message);
	
	}
	
	/**
	 * Do an asynchronous 'callback'-style call.
	 * The client fires the input message, and registers
	 * a <i>callback listener</i> which is notified
	 * when the response is available. The listener
	 * has to implement the interface
	 * <link>at.ac.tuwien.infosys.dsg.daios.framework.interfaces</link>
	 * and implement the <i>onComplete</i> and <i>onError</i>
	 * methods accordingly.
	 * 
	 * @param message The Daios-style input message.
	 * @param callback The registered callback listener.
	 * 
	 * @throws AmbigiousException
	 * @throws InvocationException
	 */
	public void callback(DaiosInputMessage message, IDaiosCallback callback)
		throws AmbigiousException, InvocationException {
		
		if(message == null) {
			DaiosInputMessage m = new DaiosInputMessage();
			imp.callback(m, callback);
		}
		
		else
			imp.callback(message, callback);
		
	}

	/**
	 * Do an asynchronous 'poll object'-style call. The client
	 * fires the input message, and receives a 'poll object'
	 * as response. This poll object can be 'queried' for the
	 * result of the invocation as soon as it is available.
	 * 
	 * <p>
	 * 
	 * The poll object call is an abstraction of the more
	 * general callback call.
	 * 
	 * @param message The Daios-style input message.
	 * @return The poll object which will contain the result
	 * as soon as it is available.
	 * 
	 * @throws AmbigiousException
	 * @throws InvocationException
	 */
	public PollObject pollObjectCall(DaiosInputMessage message)
		throws AmbigiousException, InvocationException {
		
		if(message == null) {
			DaiosInputMessage m = new DaiosInputMessage();
			return imp.pollObjectCall(m);
		}
		
		return imp.pollObjectCall(message);
		
	}
	
	/**
	 * Set the endpoint address of the service. It is not
	 * mandatory to set the endpoint using this method -
	 * if it is not set the endpoint will be read from
	 * the WSDL definition. If the defintion contains more
	 * than one endpoint address usage of this method <i>is</i>
	 * mandatory. The endpoint address also has to be set when
	 * using RESTful invocations.
	 * 
	 * @param endpoint The address of the endpoint.
	 */
	public void setEndpointAddress(URL endpoint) {
		
		imp.setEndpointAddress(endpoint);
		
	}
	
	/**
	 * Hard-set the name of the WSDL operation to use. Not
	 * allowed in RESTful invocations.
	 * 
	 * @param operation The QName of the operation to use.
	 * 
	 * @throws AmbigiousException 
	 */
	public void setWSDLOperationName(QName operation) throws AmbigiousException {
		
		imp.setOperation(operation);
		
	}
	
	/**
	 * Hard-set the name of the input message to use. Not
	 * allowed in RESTful invocations.
	 * 
	 * @param message The QName of the input message to use.
	 * 
	 * @throws AmbigiousException
	 */
	public void setWSDLInputMessage(QName message) throws AmbigiousException {
		
		imp.setInputMessage(message);
		
	}
	
	public IServiceFrontendImplementor getImplementor() {
		
		return imp;
		
	}
	
	public void setInterceptor(DaiosInterceptor interceptor) {
		imp.setInterceptor(interceptor);
	}
	
}
